import MapRect from "./MapRect.js";
import RectType from "./RectType.js";

export default class AStarManager {
    public openList: Array<MapRect> = new Array<MapRect>()
    public closeList: Array<MapRect> = new Array<MapRect>()
    public map: Array<Array<MapRect>> | null = null
    public static Instance: AStarManager
    private mapWidth:number = 0
    private mapHeight:number = 0
    constructor(map: Array<Array<MapRect>>) {
        if (!AStarManager.Instance) {
            AStarManager.Instance = this
        }
        AStarManager.Instance.map = map
        this.mapWidth = map.length
        this.mapHeight = map[0].length
        return AStarManager.Instance
    }

    public calc(start: MapRect, end: MapRect) {
        // 是否有地界数据
        if (!this.map) return null
        // 是否超出边界
        // if(start.x < 0 || start.x >= Map.length || start.y )

        // 重置数据
        this.openList = new Array<MapRect>()
        this.closeList = new Array<MapRect>()
        // this.openList.push(start)

        // 开始查找
        while (true) {
            // 把开始点加入 closeList
            this.closeList.push(start)
            // 查找周围的 方块
            this.findNearRectToOpenList(start, end)           
            // 如果找不到相邻方块为死路
            if(this.openList.length == 0){
                console.log('死路')
                return null            
            }
            // 如果有可以通过的相邻方块，找出消耗最小的一个
            this.openList.sort(sortBy)
            start = this.openList.pop() as MapRect
            // 如果到达终点
            if (start == end) {
                const path = new Array<MapRect>()
                path.push(end)
                while (end.parent !== null) {
                    path.push(end.parent)
                    end = end.parent
                }
                return path.reverse()
            }
        }
    }

    private findNearRectToOpenList(start: MapRect, end: MapRect) {
        if (!this.map) return
        const x = start.x
        const y = start.y
        // 上
        this.addToOpenList(x,y-1,start,end)
        // 下
        this.addToOpenList(x,y+1,start,end)
        // 左
        this.addToOpenList(x-1,y,start,end)
        // 右
        this.addToOpenList(x+1,y,start,end)
    }
    private addToOpenList(x:number,y:number,start:MapRect,end:MapRect) {
        
        if(!this.map) return
        // 不在地图范围内的不用计算
        if(x < 0 || y < 0
            || x >= this.mapWidth || y >= this.mapHeight) {
            return
        } 
        const rect = this.map[x][y]
        // 如果已经计算过了，就不用重新计算f(消耗)值了
        if(this.openList.includes(rect) || this.closeList.includes(rect) || rect.type == RectType.Obstacles) return
        rect.parent = start
        rect.g = rect.parent.g + 1
        rect.h = Math.abs(end.x - x) + Math.abs(end.y - y)
        rect.f = rect.g + rect.h
        this.openList.push(rect)
    }
}



function sortBy(a: MapRect, b: MapRect) {
    return b.f - a.f
}